import hashlib
import json
import os


class UserManager:
    """用户管理系统：处理用户注册、登录和凭证存储"""
    DATA_FILE = "users.json"

    def __init__(self):
        """初始化用户存储文件"""
        self.users = self._load_users()

    def _load_users(self):
        """从文件加载用户数据"""
        if not os.path.exists(self.DATA_FILE):
            return {}
        try:
            with open(self.DATA_FILE, 'r') as f:
                return json.load(f)
        except json.JSONDecodeError:
            return {}

    def _save_users(self):
        """保存用户数据到文件"""
        with open(self.DATA_FILE, 'w') as f:
            json.dump(self.users, f, indent=2)

    @staticmethod
    def _hash_password(password):
        """使用SHA-256生成密码哈希值"""
        return hashlib.sha256(password.encode('utf-8')).hexdigest()

    def register(self, username, password):
        """注册新用户"""
        if username in self.users:
            return False, "用户名已存在"

        self.users[username] = {
            "password_hash": self._hash_password(password),
            "login_attempts": 0
        }
        self._save_users()
        return True, "注册成功"

    def login(self, username, password):
        """用户登录验证"""
        user = self.users.get(username)
        if not user:
            return False, "用户不存在"

        # 检查登录尝试次数限制
        if user.get("login_attempts", 0) >= 3:
            return False, "账户已锁定，请稍后重试"

        # 验证密码
        if user["password_hash"] != self._hash_password(password):
            user["login_attempts"] = user.get("login_attempts", 0) + 1
            self._save_users()
            return False, "密码错误"

        # 重置登录尝试计数器
        user["login_attempts"] = 0
        self._save_users()
        return True, "登录成功"

    def reset_login_attempts(self, username):
        """重置用户登录尝试次数（管理员功能）"""
        if username in self.users:
            self.users[username]["login_attempts"] = 0
            self._save_users()
            return True
        return False


import unittest
import os
from user_auth import UserManager


class TestUserAuthentication(unittest.TestCase):
    """用户认证系统单元测试"""
    TEST_FILE = "test_users.json"

    def setUp(self):
        """每个测试前重置测试环境"""
        self.user_manager = UserManager()
        self.user_manager.DATA_FILE = self.TEST_FILE
        # 清理测试文件
        if os.path.exists(self.TEST_FILE):
            os.remove(self.TEST_FILE)

    def tearDown(self):
        """每个测试后清理测试文件"""
        if os.path.exists(self.TEST_FILE):
            os.remove(self.TEST_FILE)

    def test_user_registration(self):
        """测试用户注册流程"""
        # 成功注册
        result, msg = self.user_manager.register("testuser", "Pass123!")
        self.assertTrue(result)
        self.assertEqual(msg, "注册成功")

        # 重复用户名注册
        result, msg = self.user_manager.register("testuser", "NewPass456")
        self.assertFalse(result)
        self.assertEqual(msg, "用户名已存在")

    def test_password_hashing(self):
        """测试密码哈希功能"""
        # 相同密码生成相同哈希
        hash1 = self.user_manager._hash_password("secret")
        hash2 = self.user_manager._hash_password("secret")
        self.assertEqual(hash1, hash2)

        # 不同密码生成不同哈希
        hash3 = self.user_manager._hash_password("different")
        self.assertNotEqual(hash1, hash3)

    def test_login_functionality(self):
        """测试登录流程"""
        self.user_manager.register("alice", "Wonderland@2023")

        # 正确凭据
        result, msg = self.user_manager.login("alice", "Wonderland@2023")
        self.assertTrue(result)
        self.assertEqual(msg, "登录成功")

        # 错误密码
        result, msg = self.user_manager.login("alice", "wrongpassword")
        self.assertFalse(result)
        self.assertEqual(msg, "密码错误")

        # 不存在的用户
        result, msg = self.user_manager.login("bob", "anypassword")
        self.assertFalse(result)
        self.assertEqual(msg, "用户不存在")

    def test_login_attempts_security(self):
        """测试登录次数限制"""
        self.user_manager.register("locked_user", "securePW")

        # 连续三次错误登录
        for _ in range(3):
            self.user_manager.login("locked_user", "wrong")

        # 第四次尝试应被锁定
        result, msg = self.user_manager.login("locked_user", "wrong")
        self.assertFalse(result)
        self.assertEqual(msg, "账户已锁定，请稍后重试")

        # 重置后应能登录
        self.user_manager.reset_login_attempts("locked_user")
        result, msg = self.user_manager.login("locked_user", "securePW")
        self.assertTrue(result)

    def test_data_persistence(self):
        """测试数据持久化"""
        # 注册新用户并保存
        self.user_manager.register("persistent_user", "data123")
        del self.user_manager

        # 创建新实例应能加载数据
        new_manager = UserManager()
        new_manager.DATA_FILE = self.TEST_FILE
        result, _ = new_manager.login("persistent_user", "data123")
        self.assertTrue(result)


if __name__ == "__main__":
    unittest.main()